#include "linux/init.h"
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/ide.h"

#include "linux/i2c.h"
#include "linux/i2c-dev.h"

#include "asm/mach/map.h"
#include "asm/uaccess.h"
#include "asm/io.h"

#include "linux/cdev.h"
#include "linux/of.h"
#include "linux/delay.h"

#include "AP3216C_REG.h"

#define NAME "ap3216c"

struct ST_AP3216C{
    int major;
    int minor;
    dev_t dev_id;
    struct cdev st_cdev;
    struct class *st_class;
    struct device *st_device;

    void *private_data;

    unsigned short ir,als,ps;
};

struct ST_AP3216C st_ap3216cDev;

//读寄存器
static int ap3216c_read_regs(struct ST_AP3216C *ap3216c_dev,u8 reg,void *val,int len)
{
    int retval = 0;

    struct i2c_msg msg[2];  //写要读的寄存器，读寄存器返回的数据，两条消息
    struct i2c_client *client = (struct i2c_client *)ap3216c_dev->private_data; //private_data是在注册字符设备的时候从i2c_driver中获取的client对象

    msg[0].addr = client->addr;
    msg[0].flags = 0;//发送数据标志
    msg[0].buf = &reg;//要读取的寄存器
    msg[0].len = 1;//reg长度

    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;//读数据
    msg[1].buf = val;//读取数据缓存
    msg[1].len = len;//读取数据长度

    retval = i2c_transfer(client->adapter,msg,2);
    if (retval == 2)
    {
        return 0;
    }
    else
    {
        printk("iic rd failed;%d reg = %06x len=%d\r\n",retval,reg,len);
        retval = -EREMOTEIO;
    }

    return retval;

}

//写寄存器
static s32 ap3216c_write_regs(struct ST_AP3216C *ap3216c_dev,u8 reg,u8 *buf,u8 len)
{
    u8 buffer[256];
    struct i2c_msg msg;
    struct i2c_client *client = (struct i2c_client *)ap3216c_dev->private_data;

    buffer[0] = reg;
    memcpy(&buffer[1],buf,len); //将要写入的数据拷贝至发送数组
    msg.addr = client->addr;
    printk("client->addr:0x%02x\r\n",client->addr);
    msg.flags = 0;//发送标志
    msg.buf = buffer;
    msg.len = len+1;//+1加的是寄存器地址那个1

    return i2c_transfer(client->adapter, &msg,1);
}

//ap3216c读寄存器值
static unsigned char ap3216c_read_reg(struct ST_AP3216C *ap3216c_dev,u8 reg)
{
    u8 data = 0;

    ap3216c_read_regs(ap3216c_dev,reg,&data,1);//将reg里面的值放入data中

    return data;//将读到的数据返回
}

//ap3216c写寄存器
static void ap3216c_write_reg(struct ST_AP3216C *ap3216c_dev,u8 reg,u8 data)
{
    u8 buf = 0;
    buf = data;
    ap3216c_write_regs(ap3216c_dev,reg,&buf,1);
}

//读取传感器数据
void ap3216c_readdata(struct ST_AP3216C *ap3216c_dev)
{
    int i=0;
    unsigned char buf[6];
    //读取所有寄存器的值
    for ( i = 0; i < 6; i++)
    {
        buf[i] = ap3216c_read_reg(ap3216c_dev,AP3216C_IRDATALOW+i);
    }
    
    if (buf[0] & 0x80)
    {
        ap3216c_dev->ir = 0;//数据无效
    }
    else
    {
        ap3216c_dev->ir = ((unsigned short)buf[1]<<2) | (buf[0] & 0x03);
    }
    
    ap3216c_dev->als = ((unsigned short)buf[3]<<8) | buf[2];

    if (buf[4] & 0x40)
    {
        ap3216c_dev->ps = 0;//数据无效
    }
    else
    {
        ap3216c_dev->ps = ((unsigned short)(buf[5] & 0x3F) << 4) | (buf[4] & 0x0F);
    }
    
}

int ap3216c_open(struct inode *nd, struct file *fp)
{
    fp->private_data = &st_ap3216cDev;
    ap3216c_write_reg(&st_ap3216cDev,AP3216C_SYSTEMCONFIG,0x04);
    mdelay(50);
    ap3216c_write_reg(&st_ap3216cDev,AP3216C_SYSTEMCONFIG,0x03);
    return 0;
}
ssize_t ap3216c_read (struct file *fp, char __user *buf, size_t len, loff_t *offset)
{
    short data[3];
    long err = 0;

    struct ST_AP3216C *dev = (struct ST_AP3216C *)fp->private_data;

    ap3216c_readdata(dev);

    data[0] = dev->ir;
    data[1] = dev->als;
    data[2] = dev->ps;

    err = copy_to_user(buf,data,sizeof(data));

    return 0;
}
ssize_t ap3216c_write(struct file *fp, const char __user *buf, size_t len, loff_t *offset)
{
    return 0;
}
int ap3216c_release (struct inode *nd, struct file *fp)
{
    return 0;
}
long ap3216c_unlocked_ioctl (struct file *fp, unsigned int cmd, unsigned long arg)
{
    return 0;
}
static struct file_operations fops_ap3216c = {
    .owner = THIS_MODULE,
    .open = ap3216c_open,
    .write = ap3216c_write,
    .read = ap3216c_read,
    .release = ap3216c_release,
    .unlocked_ioctl = ap3216c_unlocked_ioctl,
};

int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
    //创建字符设备和设备节点

    alloc_chrdev_region(&st_ap3216cDev.dev_id,0,1,NAME);
    st_ap3216cDev.major = MAJOR(st_ap3216cDev.dev_id);
    st_ap3216cDev.minor = MINOR(st_ap3216cDev.dev_id);
    printk("Major:%d minor:%d\n",st_ap3216cDev.major,st_ap3216cDev.minor);

    st_ap3216cDev.st_cdev.owner = THIS_MODULE;
    cdev_init(&st_ap3216cDev.st_cdev,&fops_ap3216c);
    cdev_add(&st_ap3216cDev.st_cdev,st_ap3216cDev.dev_id,1);

    st_ap3216cDev.st_class = class_create(THIS_MODULE,NAME);
    if (IS_ERR(st_ap3216cDev.st_class)) {
		return PTR_ERR(st_ap3216cDev.st_class);
	}
    
    st_ap3216cDev.st_device = device_create(st_ap3216cDev.st_class,NULL,st_ap3216cDev.dev_id,NULL,NAME);
    if (IS_ERR(st_ap3216cDev.st_device)) {
		return PTR_ERR(st_ap3216cDev.st_device);
	}
    st_ap3216cDev.private_data = client;

    return 0;
}

int ap3216c_remove(struct i2c_client *client)
{
    unregister_chrdev_region(st_ap3216cDev.dev_id,1);
    cdev_del(&st_ap3216cDev.st_cdev);
    device_destroy(st_ap3216cDev.st_class,st_ap3216cDev.dev_id);
    class_destroy(st_ap3216cDev.st_class);
    return 0;
}

struct of_device_id	ap3216c_match_table[] = {
    {
        .compatible = "lux,ap3216c",
    },
    {

    },
};
struct i2c_device_id ap3216c_id[] = {
    {"lux,ap3216c",0},
    {}
};

static struct i2c_driver ap3216c_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = "AP3216C",
        .of_match_table = ap3216c_match_table,
    },
    .probe = ap3216c_probe,
    .remove = ap3216c_remove,
    .id_table = ap3216c_id,
};

static int __init ap3216c_driver_init(void)
{
    return i2c_add_driver(&ap3216c_driver);
}

static void __exit ap3216c_driver_exit(void)
{
    i2c_del_driver(&ap3216c_driver);
}

module_init(ap3216c_driver_init);
module_exit(ap3216c_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lux");
MODULE_DESCRIPTION("AP3216C driver");


